#pragma once

#include <limits>
#include <vector>



namespace rt
{
	struct Ray;
	struct Ray4;
	struct Ray4_SingleOrigin;
	struct IntersectionData;

	struct Metaball
	{
		XMVECTOR Center;
		float Radius;
	};

	struct Blob
	{
		Blob() { BallsNum = 0; }

		void* operator new[] (size_t size)
		{
			void * p = _aligned_malloc(size, 16);
			if (p == 0) LOG("ACHTUNG!!! OUT OF MEMORY!!!");
			return p;
		}
		void operator delete[] (void *p)
		{
			_aligned_free(p);
		}

		Metaball * CreateMetaball();

		static const int TAB_SIZE = 4;
		Metaball Balls[TAB_SIZE];
		int BallsNum;

		void UpdateRadii()
		{
			mRadii = XMVectorSet(Balls[0].Radius, Balls[1].Radius, Balls[2].Radius, Balls[3].Radius);
		}
		XMVECTOR mRadii;

		inline float fieldStrength(const XMVECTOR & point) const
		{
			const XMVECTOR dist0 = XMVectorSubtract(Balls[0].Center, point);
			const XMVECTOR dist1 = XMVectorSubtract(Balls[1].Center, point);
			const XMVECTOR dist2 = XMVectorSubtract(Balls[2].Center, point);
			const XMVECTOR dist3 = XMVectorSubtract(Balls[3].Center, point);

			XMVECTOR distX = XMVectorSet(XMVectorGetX(dist0), XMVectorGetX(dist1), XMVectorGetX(dist2), XMVectorGetX(dist3));
			XMVECTOR distY = XMVectorSet(XMVectorGetY(dist0), XMVectorGetY(dist1), XMVectorGetY(dist2), XMVectorGetY(dist3));
			XMVECTOR distZ = XMVectorSet(XMVectorGetZ(dist0), XMVectorGetZ(dist1), XMVectorGetZ(dist2), XMVectorGetZ(dist3));

			XMVECTOR distLenSq = XMVectorMultiply(distX, distX);
			distLenSq = XMVectorMultiplyAdd(distY, distY, distLenSq);
			distLenSq = XMVectorMultiplyAdd(distZ, distZ, distLenSq);

			const XMVECTOR strengths = XMVectorDivide(
				mRadii,
				distLenSq);

			return XMVectorGetX(strengths) + XMVectorGetY(strengths) + XMVectorGetZ(strengths) + XMVectorGetW(strengths);
		}

		inline bool isInside(const XMVECTOR & point) const
		{
			return fieldStrength(point) > 1.0f;
		}


	};

	void IntersectBlobs_All_4RaysSingleOrigin(const Blob * blobs, int num, const Ray4_SingleOrigin & rays, XMVECTOR & intersIndex, XMVECTOR & depth);
	void IntersectBlobs_All_4Rays(const Blob * blobs, int num, const Ray4 & rays, XMVECTOR & intersIndex, XMVECTOR & depth, XMVECTOR & intersType);

	void GetBlobIntersectionData(const Blob & blob, XMVECTOR intersPoint, IntersectionData & data);

}
